<?php
/**
 * NetBiz Framework
 * Copyright (C) 20009 - 2010 NetBiz
 * 
 * All rights reserved.
 */
class FRM_Config {
	/**
	 * Constants for development status of configuration
	 */
	const STABLE		= 'stable';
	const BETA		= 'beta';
	const DEV		= 'dev';
	const DEPREC		= 'deprecated';

	/**
	 * Constants for type of configuration variables
	 */
	const BOOL			= 'bool';
	const PATH			= 'path';
	const STRING		= 'string';
	const INT			= 'integer';
	const FLOAT			= 'float';
	const ARRAY_ASSOC	= 'associative array';
	const ENUM			= 'enum';


	static $_conf = array();
	
	static public function loadConfig($filename)
	{
		include($filename);
		self::mergeConfig($c);
	}

	static public function mergeConfig($c)
	{
		foreach($c as $dk => $domain)
		{
			if (!isset(self::$_conf[$dk]))
			{
				self::$_conf[$dk] = $domain;
			}
			else
			{
				foreach($domain['v'] as $vk => $variable)
				{
					foreach($variable as $pk => $property)
					{
						self::$_conf[$dk]['v'][$vk][$pk] = $property;
					}
				}
			}
		}
	}
	
	static public function exists($domain,$name)
	{
		return isset(self::$_conf[$domain]['v'][$name]);
	}

	static public function get($domain,$name)
	{
		if (isset(self::$_conf[$domain]))
		{
			if (isset(self::$_conf[$domain]['v'][$name]))
			{
				if (@ self::$_conf[$domain]['v'][$name]['eval'])
				{
					self::$_conf[$domain]['v'][$name]['value'] = eval('return '.(@ self::$_conf[$domain]['v'][$name]['value']).';');
					self::$_conf[$domain]['v'][$name]['eval'] = FALSE;
				}
	
				return @ self::$_conf[$domain]['v'][$name]['value'];
			}
			else
			{
				throw new FRM_Exception("Cannot find configuration variable `$name` in domain `$domain`",FRM_Exception::CONFIG_VAR);
			}
		}
		else
		{
			throw new FRM_Exception("Cannot find configuration domain `$domain`",FRM_Exception::CONFIG_DOMAIN);
		}
	}

	static public function set($domain,$name,$value,$strict = TRUE)
	{
		if (!isset(self::$_conf[$domain]))
		{
			throw new FRM_Exception("Cannot find configuration domain `$domain`",FRM_Exception::CONFIG_DOMAIN);
		}

		if (!isset(self::$_conf[$domain]['v'][$name]))
		{
			throw new FRM_Exception("Cannot find configuration variable `$name` in domain `$domain`",FRM_Exception::CONFIG_VAR);
		}

		if (!$strict or self::typeCheck($value, @ self::$_conf[$domain]['v'][$name]))
		{
			if (@ self::$_conf[$domain]['readonly'])
			{
				throw new FRM_Exception("Error when setting value for `$domain`.`$name`, domain is locked",FRM_Exception::CONFIG_LOCK);
			}

			if (@ self::$_conf[$domain]['v'][$name]['readonly'])
			{
				throw new FRM_Exception("Error when setting value for `$domain`.`$name`, variable is locked",FRM_Exception::CONFIG_LOCK);
			}
			
			self::$_conf[$domain]['v'][$name]['value'] = $value;
			self::$_conf[$domain]['v'][$name]['eval']  = FALSE;
		}
		else
		{
			throw new FRM_Exception("Configuration value type check failed for `$domain`.`$name`, value is $value",FRM_Exception::CONFIG_TYPE);
		}
	}
	
	static public function export()
	{
		foreach(self::$_conf as $domain => $domain_config)
		{
			foreach($domain_config['v'] as $name => $config)
			{
				if (@$config['export'] and !defined($domain.'_'.$name))
				{
					define($domain.'_'.$name, self::get($domain,$name));
					self::lock($domain,$name);
				}
			}
		}
	}

	static public function lock($domain,$name = '')
	{
		if ($name)
		{
			self::$_conf[$domain]['v'][$name]['readonly'] = TRUE;
		}
		else
		{
			self::$_conf[$domain]['readonly'] = TRUE;
		}
	}

	static public function typeCheck($value,$val_info)
	{
		switch(@$val_info['type'])
		{
			case self::BOOL :
				return is_bool($value);
				break;
			case self::INT :
				return is_int($value);
				break;
			case self::FLOAT :
				return is_float($value);
				break;
			case self::STRING :
				return is_string($value);
				break;
			case self::ARRAY_ASSOC :
				return is_array($value);
				break;
			case self::ENUM :
				return in_array($value,@$val_info['enum_values']);
				break;
			default :
				return TRUE;
				break;
		}
	}
}